package org.jeecgframework.web.cgform.controller.generate;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tongan.database.JeecgReadTable;
import com.tongan.entity.button.CgformButtonEntity;
import com.tongan.entity.button.CgformButtonSqlEntity;
import com.tongan.entity.config.CgFormFieldEntity;
import com.tongan.entity.config.CgFormHeadEntity;
import com.tongan.entity.enhance.CgformEnhanceJavaEntity;
import com.tongan.entity.enhance.CgformEnhanceJsEntity;
import com.tongan.generate.CgformCodeGenerate;
import com.tongan.generate.TemplateEngineType;
import com.tongan.generate.tinyextend.NewMetadata;
import com.tongan.generate.tinyextend.TemplateDefine;
import com.tongan.generate.tinyextend.TinyTemplateUtil;
import com.tongan.pojo.CreateFileProperty;
import com.tongan.pojo.GenerateEntity;
import com.tongan.util.CodeResourceUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.jeecgframework.core.common.controller.BaseController;
import org.jeecgframework.core.common.model.json.AjaxJson;
import org.jeecgframework.core.enums.OnlineGenerateEnum;
import org.jeecgframework.core.util.StringUtil;
import org.jeecgframework.p3.core.util.MD5Util;
import org.jeecgframework.web.cgform.service.build.DataBaseService;
import org.jeecgframework.web.cgform.service.button.CgformButtonServiceI;
import org.jeecgframework.web.cgform.service.button.CgformButtonSqlServiceI;
import org.jeecgframework.web.cgform.service.config.CgFormFieldServiceI;
import org.jeecgframework.web.cgform.service.enhance.CgformEnhanceJsServiceI;
import org.jeecgframework.web.cgform.service.impl.generate.TempletContextWord;
import org.jeecgframework.web.system.service.DynamicDataSourceServiceI;
import org.jeecgframework.web.system.service.SystemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 * @Title:CgGenerateController
 * @description:智能表单代码生成器[根据智能表单配置+代码生成设置->生成代码]
 * @author 赵俊夫
 * @date Sep 7, 2013 12:19:32 PM
 * @version V1.0
 */
@Controller
@RequestMapping("/generateController")
public class GenerateController extends BaseController {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(GenerateController.class);
	
	@Autowired
	private CgFormFieldServiceI cgFormFieldService;
	@Autowired
	private CgformButtonServiceI cgformButtonService;
	@Autowired
	private CgformButtonSqlServiceI cgformButtonSqlService;
	@Autowired
	private CgformEnhanceJsServiceI cgformEnhanceJsService;
	@Autowired
	private TempletContextWord templetContextWord;
	@Autowired
	private DataBaseService dataBaseService;
	/**
	 * 代码生成配置页面
	 * @param request
	 * @return
	 */
	@RequestMapping(params = "gogenerate")
	public ModelAndView gogenerate( String id,HttpServletRequest request) {
		String returnModelAndView = null;
		request.getSession().setAttribute("templateTypes", Arrays.asList(TemplateEngineType.values()));
		if(true){
			//如果是单表或者附表，则进入单表模型
			request.setAttribute("jspModeList", getOnlineGenerateEnum("single",TemplateEngineType.FreeMarker));// 表单风格
			returnModelAndView = "jeecg/cgform/generate/batch";
		}
		String projectPath = CodeResourceUtil.getProject_path();
		try{
		    Cookie[] cookies=request.getCookies();
		    if(cookies!=null){
		    for(int i=0;i<cookies.length;i++){
		    	String cookieName=cookies[i].getName();
		        if(cookieName.contains("cookie_")) {
					String value = cookies[i].getValue();
					if (value != null && !"".equals(value)) {
						projectPath = cookies[i].getValue();
						projectPath = URLDecoder.decode(projectPath, "UTF-8");
					}
					request.setAttribute(cookieName.replace("cookie_",""),projectPath);
				}
		    }
		    }
		}catch(Exception e){
		    e.printStackTrace();
		}
		request.setAttribute("ids",id);
		return new ModelAndView(returnModelAndView);
	}

    /**
     * 获取模版
     * @param templateDir
     * @param request
     * @return
     */
	@RequestMapping(params = "getTemplateFileList")
	@ResponseBody
	public Object getTemplateFileList(String templateDir,HttpServletRequest request){
		return getConfigableMedata(templateDir,true);
	}

    /**
     * 获取配置 并将id设为路径的md5值
     * @param templateDir 模版路径
     * @param needSort 是否需要排序
     * @return
     */
	private NewMetadata getConfigableMedata(String templateDir,boolean needSort){
		NewMetadata newMetadata=TinyTemplateUtil.findTemplateData(templateDir);
		if (newMetadata!=null){
			newMetadata.getTemplateDefines().forEach(s->{
				if (s.getOutput()){
					s.setId(MD5Util.MD5Encode(s.getTemplatePath(),"utf-8"));
				}
			});
			if (needSort){
				newMetadata.setTemplateDefines(newMetadata.getTemplateDefines().stream().filter((s)->{
					return s.getOutput();
				}).sorted(Comparator.comparing(s2 -> FilenameUtils.getExtension(((TemplateDefine)s2).getTemplatePath()))).collect(Collectors.toList()));

			}

		}else{
			newMetadata=new NewMetadata();
		}

		return newMetadata;
	}

	public void configMetadata(NewMetadata metadata,Set<String> outputTemplates){
		if (metadata!=null && outputTemplates!=null){
			metadata.getTemplateDefines().forEach(s->{
				if (!outputTemplates.contains(s.getId())){
					//前端不包含则不输出
					s.setOutput(false);
				}
			});
		}
	}
	
	private List<OnlineGenerateEnum> getOnlineGenerateEnum(String type,TemplateEngineType engineType){
		List<OnlineGenerateEnum> list = new ArrayList<OnlineGenerateEnum>();
		for(OnlineGenerateEnum item : OnlineGenerateEnum.values()) {
			if(item.getFormType().equals(type) ) {
				list.add(item);
			}
		}
		return list;
	}

	@Resource
	SystemService systemService;

	@Resource
	DynamicDataSourceServiceI dynamicDataSourceServiceI;
	/**
	 * 代码生成执行-单表
	 * @param generateEntity
	 * @param request
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping(params = {"dogenerate"})
	public void dogenerate(String ids, GenerateEntity generateEntity,
						   CreateFileProperty createFileProperty,
						   TemplateEngineType engineType,
						   HttpServletRequest request, HttpServletResponse response) throws Exception {
		//step.1 准备好智能表单的配置
		List<String> errors=new ArrayList<>();
		AjaxJson j = new AjaxJson();
		CgFormHeadEntity[] cgFormHeads = null;
		if (org.apache.commons.lang3.StringUtils.isNotBlank(ids)) {
			String[] id = ids.split(",");
			cgFormHeads = new CgFormHeadEntity[id.length];
			for (int i = 0; i < id.length; i++) {
				cgFormHeads[i] = cgFormFieldService.getEntity(CgFormHeadEntity.class, id[i]);
				CgFormHeadEntity cgFormHead = cgFormHeads[i];
				if (cgFormHead != null) {
					if (cgFormHead.isSuperClass()) {
						cgFormHeads[i] = null;
					}
				} else {
					j.setSuccess(false);
					j.setMsg("表单配置不存在");
					continue;
				}
			}
		} else {
			j.setSuccess(false);
			j.setMsg("表单配置不存在");
		}

		try {
			OnlineGenerateEnum modeEnum = OnlineGenerateEnum.toEnum(createFileProperty.getJspMode());
			if (modeEnum != null) {
                if (modeEnum.getEngineType().equals(engineType)) {
                    if ("ext".equals(modeEnum.getVersion())) {

                        for (int i = 0; i < cgFormHeads.length; i++) {
                            try {
                                if (cgFormHeads[i] != null) {
                                    //获取模版生成的不能排序 因为会影响到后面模版依赖问题
                                    NewMetadata metadata = getConfigableMedata(createFileProperty.getJspMode(), false);
                                    if (metadata != null) {
                                        configMetadata(metadata, null);//前端传来的配置
                                        getCgformConfig(cgFormHeads[i], generateEntity);
                                        cgFormFieldService.fillTableWithIdKey(cgFormHeads[i]);
                                        CgformCodeGenerate generate = new CgformCodeGenerate(createFileProperty, generateEntity, engineType);
                                        generate.setConfigedMetadata(metadata);
                                        generate.generateToFileUserDefined();
                                    } else {
                                        j.setMsg("模版配置文件不存在");
                                    }
                                }
                            } catch (Exception e1) {
                                e1.printStackTrace();
                                errors.add(cgFormHeads[i].getContent()+" ===== " + e1.getMessage());
                                throw new RuntimeException(e1.getMessage());
                            }
                        }
                    }
                    j.setMsg("代码模版生成成功");
                } else {
                    j.setMsg("所选模版引擎与风格不符");
                }
            } else {
                j.setMsg("代码生成器不支持该页面风格");
            }
		} catch (RuntimeException e) {
			j.setMsg(e.getMessage());
		}

		errors.forEach(s->{
			j.setMsg(j.getMsg()+"\r\n"+s);
		});

		try {
			String projectPath = URLEncoder.encode(generateEntity.getProjectPath(), "UTF-8");
			List<Cookie> cookies = Arrays.asList(new Cookie[]{
					new Cookie("cookie_projectPath", projectPath),
					new Cookie("cookie_controllerPrefix", URLEncoder.encode(generateEntity.getControllerPrefix(), "UTF-8")),
					new Cookie("cookie_uiPath", URLEncoder.encode(generateEntity.getUiPath(), "UTF-8")),
					new Cookie("cookie_engineType", engineType.name()),
					new Cookie("cookie_jspMode", createFileProperty.getJspMode()),
			});
			cookies.forEach(cookie -> {
				response.addCookie(cookie);
			});
			response.getWriter().print(j.getJsonStr());
			response.getWriter().flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				response.getWriter().close();
			} catch (Exception e2) {
			}
		}

	}

	@Resource
	CgformButtonServiceI cgformButtonServiceI;

	/**
	 * 获取智能表单中外键：根据是否设置了主表以及主表字段来判断
	 * @param colums
	 * @return
	 */
	private String[] getForeignkeys(List<CgFormFieldEntity> colums) {
		List<String> fs = new ArrayList<String>(0);
		for(CgFormFieldEntity c : colums){
			if(c.getForeignTableEntity()!=null && c.getForeignFieldEntity()!=null){
				fs.add(c.getFieldName().toUpperCase());
			}
		}
		String[] foreignkeys = (String[]) fs.toArray(new String[fs.size()]);
		return foreignkeys;
	}
	/**
	 * 获取智能表单的所有配置
	 * @param cgFormHead
	 * @param generateEntity
	 * @throws Exception 
	 */
	private void getCgformConfig(CgFormHeadEntity cgFormHead,
			GenerateEntity generateEntity) throws Exception {
		int filedNums = cgFormHead.getColumns().size();
		List<CgformButtonEntity> buttons = null;
		Map<String, String[]> buttonSqlMap = new LinkedHashMap<String, String[]>();
		//表单配置
		cgFormHead = cgFormFieldService.getEntity(
				CgFormHeadEntity.class, cgFormHead.getId());
		//按钮配置
		buttons = cgformButtonService.getCgformButtonListByFormId(cgFormHead.getId());
		//按钮SQL增强
		for(CgformButtonEntity cb:buttons){
			CgformButtonSqlEntity cbs = cgformButtonSqlService.getCgformButtonSqlByCodeFormId(cb.getButtonCode(), cgFormHead.getId());
			buttonSqlMap.put(cb.getButtonCode(), cbs==null?new String[]{}:cbs.getCgbSqlStr().replaceAll("(\r\n|\r|\n|\n\r)", "").split(";"));
		}
		CgformButtonSqlEntity cbsAdd = cgformButtonSqlService.getCgformButtonSqlByCodeFormId("add", cgFormHead.getId());
		buttonSqlMap.put("add", cbsAdd==null?new String[]{}:cbsAdd.getCgbSqlStr().replaceAll("(\r\n|\r|\n|\n\r)", "").split(";"));
		CgformButtonSqlEntity cbsUpdate = cgformButtonSqlService.getCgformButtonSqlByCodeFormId("update", cgFormHead.getId());
		buttonSqlMap.put("update", cbsUpdate==null?new String[]{}:cbsUpdate.getCgbSqlStr().replaceAll("(\r\n|\r|\n|\n\r)", "").split(";"));
		CgformButtonSqlEntity cbsDelete = cgformButtonSqlService.getCgformButtonSqlByCodeFormId("delete", cgFormHead.getId());
		buttonSqlMap.put("delete", cbsDelete==null?new String[]{}:cbsDelete.getCgbSqlStr().replaceAll("(\r\n|\r|\n|\n\r)", "").split(";"));
		//按钮java增强
		Map<String, CgformEnhanceJavaEntity> buttonJavaMap = new LinkedHashMap<String, CgformEnhanceJavaEntity>();
		List<CgformEnhanceJavaEntity> javaList = dataBaseService.getCgformEnhanceJavaEntityByFormId(cgFormHead.getId());
		if(javaList!=null&&javaList.size()>0){
			for(CgformEnhanceJavaEntity e:javaList){
				if(StringUtil.isNotEmpty(e.getCgJavaValue())){
					buttonJavaMap.put(e.getButtonCode(), e);
				}
			}
		}
		
		//JS增强-列表
		CgformEnhanceJsEntity listJs = 	cgformEnhanceJsService.getCgformEnhanceJsByTypeFormId("list", cgFormHead.getId());
		CgformEnhanceJsEntity listJsCopy = null;
		try{
			listJsCopy = listJs.deepCopy();
		}catch (Exception e) {
			logger.debug(e.getMessage());
		}
		//JS增强-表单
		CgformEnhanceJsEntity formJs = 	cgformEnhanceJsService.getCgformEnhanceJsByTypeFormId("form", cgFormHead.getId());
		CgformEnhanceJsEntity formJsCopy = null;
		try{
			formJsCopy = formJs.deepCopy();
		}catch (Exception e) {
			logger.debug(e.getMessage());
		}
		//将js中带有online字段名的 转换成java命名
		for(CgFormFieldEntity field : cgFormHead.getColumns()){
			String fieldName = field.getFieldName();
			if(listJsCopy!=null){
				listJsCopy.setCgJsStr(listJsCopy.getCgJsStr().replace(fieldName, JeecgReadTable.formatField(fieldName)));
			}
			if(formJsCopy!=null){
				formJsCopy.setCgJsStr(formJsCopy.getCgJsStr().replace(fieldName, JeecgReadTable.formatField(fieldName)));
			}
		}
		generateEntity.setButtonSqlMap(buttonSqlMap);
		generateEntity.setButtonJavaMap(buttonJavaMap);
		generateEntity.setCgFormHead(cgFormHead);
		generateEntity.setListJs(listJsCopy);
		generateEntity.setFormJs(formJsCopy);
	}
	/**
	 * 跳转到文件夹目录树
	 * @param request
	 * @return
	 */
	@RequestMapping(params = "goFileTree")
	public ModelAndView goFileTree(HttpServletRequest request) {
		return new ModelAndView("jeecg/cgform/generate/fileTree");
	}
	/**
	 * 返回子目录json
	 * @param parentNode
	 * @return
	 */
	@RequestMapping(params = "doExpandFileTree")
	@ResponseBody
	public Object doExpandFileTree(String parentNode){
		JSONArray fjson = new JSONArray();
		try{
			if(StringUtil.isEmpty(parentNode)){
				//返回磁盘驱动器根目录
				File[] roots = File.listRoots();
				for(File r:roots){
					JSONObject item = new JSONObject();
					item.put("id", r.getAbsolutePath());
					item.put("text", r.getPath());
					item.put("iconCls", "icon-folder");
					if(hasDirs(r)){
						item.put("state", "closed");
					}else{
						item.put("state", "open");
					}
					fjson.add(item);
				}
			}else{
				try {
					parentNode =  new String(parentNode.getBytes("ISO-8859-1"), "UTF-8");
				} catch (UnsupportedEncodingException e1) {
					e1.printStackTrace();
				}
				//返回子目录集
				File parent = new File(parentNode);
				File[] chs = parent.listFiles();
				for(File r:chs){
					JSONObject item = new JSONObject();
					if(r.isDirectory()){
						item.put("id", r.getAbsolutePath());
						item.put("text", r.getPath());
						if(hasDirs(r)){
							item.put("state", "closed");
						}else{
							item.put("state", "open");
						}
						fjson.add(item);
					}else{
						
					}
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("该文件夹不可选择");
		}
		return fjson;
	}
	private boolean hasDirs(File dir){
		try{
			if(dir.listFiles().length==0){
	//			item.put("state", "open");
				return false;
			}else{
	//			item.put("state", "closed");
				return true;
			}
		}catch (Exception e) {
			logger.info(e.getMessage());
			return false;
		}
	}
}
